package com.tools.web;

import com.fasterxml.jackson.core.type.TypeReference;
import com.tools.common.container.ConcurrentHashSet;
import com.tools.common.exception.service.ValidException;
import com.tools.common.io.IOKit;
import com.tools.common.object.C;
import com.tools.common.object.Note;
import com.tools.common.object.json.JsonKit;
import com.tools.common.object.string.VerifyKit;
import com.tools.web.interceptor.auth.AuthUser;
import com.tools.web.interceptor.auth.AuthenticationManager;
import com.tools.web.work.ResultCode;

import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.*;
import java.util.concurrent.ConcurrentSkipListSet;

/**
 * 公用工具类。
 * 值得注意很多方法需要身份认证后才能获取到，否则会出现异常
 * */
@Note("公用工具类。值得注意很多方法需要身份认证后才能获取到，" +
        "否则会出现异常")
public class GlobalKit {

    protected GlobalKit() {}

    @Note("将字符串转为 long 类型的 ID")
    public static long checkAndGetLongId(String id) {
        VerifyKit.checkIsTrue(VerifyKit.isInteger(id), ResultCode.PARAM_ERROR.getResult("参数类型错误"));
        return Long.parseLong(id);
    }


    @Note("将字符串转为 int 类型的 ID")
    public static int checkAndGetIntId(String id) {
        VerifyKit.checkIsTrue(VerifyKit.isInteger(id), ResultCode.PARAM_ERROR.getResult("参数类型错误"));
        return Integer.parseInt(id);
    }

    @Note("获取当前请求的 IP 地址")
    public static String getClientIP(HttpServletRequest request) {
        return (String) request.getAttribute(WebKit.CLIENT_IP_NAME);
    }

    public static String getClientIP() {
        return getClientIP(WebKit.getHttpServletRequest());
    }

    @Note("获取自定义得到的客户端外网 IP （不是很准确）")
    public static String getPublicClientIP(HttpServletRequest request) {
        return (String) request.getAttribute(WebKit.PUBLIC_NET_IP_NAME);
    }

    public static String getPublicClientIP() {
        return getPublicClientIP(WebKit.getHttpServletRequest());
    }

    @Note("获取当前用户封装的 AuthUser 对象")
    public static AuthUser getAuthUser(HttpServletRequest request) {
        return (AuthUser) request.getAttribute(AuthenticationManager.AUTH_USER_NAME);
    }

    public static AuthUser getAuthUser() {
        return getAuthUser(WebKit.getHttpServletRequest());
    }


    @Note("获取 int 类型当前用户的主键 ID")
    public static Integer getIntUserId(HttpServletRequest request) {
        return getAuthUser(request).intUserId();
    }

    public static Integer getIntUserId() {
        return getIntUserId(WebKit.getHttpServletRequest());
    }

    @Note("获取 long 类型当前用户的主键 ID")
    public static Long getLongUserId(HttpServletRequest request) {
        return getAuthUser(request).longUserId();
    }

    public static Long getLongUserId() {
        return getLongUserId(WebKit.getHttpServletRequest());
    }

    @Note("获取 String 类型当前用户的主键 ID")
    public static String getStringUserId(HttpServletRequest request) {
        return getAuthUser(request).getUserId().toString();
    }

    public static String getStringUserId() {
        return getStringUserId(WebKit.getHttpServletRequest());
    }

    @Note("已经认证后，可以从请求对象中获取设备类型 ID")
    public static String getLoginDeviceType(HttpServletRequest request) {
        return getAuthUser(request).getLoginDeviceType();
    }

    public static String getLoginDeviceType() {
        return getLoginDeviceType(WebKit.getHttpServletRequest());
    }

    @Note("已经认证后，可以从请求对象中获取用户类型")
    public static String getLoginUserType(HttpServletRequest request) {
        return getAuthUser(request).getLoginUserType();
    }

    public static String getLoginUserType() {
        return getLoginUserType(WebKit.getHttpServletRequest());
    }

    @Note("获取当前 AuthToken 的唯一标识 UUID")
    public static String getAuthTokenUuid(HttpServletRequest request) {
        return getAuthUser(request).getUuid();
    }

    public static String getAuthTokenUuid() {
        return getAuthTokenUuid(WebKit.getHttpServletRequest());
    }

    @Note("获取 AuthUser 对象里的所有自定义数据")
    public static Map<String, Object> getCustomData(HttpServletRequest request) {
        return getAuthUser(request).getCustomData();
    }

    public static Map<String, Object> getCustomData() {
        return getAuthUser(WebKit.getHttpServletRequest()).getCustomData();
    }

    public static <T> T getCustomData(HttpServletRequest request, C<T> javaBeanType) {
        return getAuthUser(request).customDataAsJavaBean(javaBeanType);
    }

    public static <T> T getCustomData(C<T> javaBeanType) {
        return getAuthUser(WebKit.getHttpServletRequest()).customDataAsJavaBean(javaBeanType);
    }

    @Note("获取 AuthUser 对象里的某个自定义数据")
    public static Object getFromAuthUserCustomData(HttpServletRequest request, String name) {
        return getAuthUser(request).dataGet(name);
    }

    public static Object getFromAuthUserCustomData(String name) {
        return getAuthUser(WebKit.getHttpServletRequest()).dataGet(name);
    }

    public static <T> T getFromAuthUserCustomData(HttpServletRequest request, String name, Class<T> dataType) {
        return getAuthUser(request).dataGet(name, dataType);
    }

    public static <T> T getFromAuthUserCustomData(String name, Class<T> dataType) {
        return getAuthUser(WebKit.getHttpServletRequest()).dataGet(name, dataType);
    }

    public static <T> T getFromAuthUserCustomData(HttpServletRequest request, String name, C<T> dataType) {
        return getAuthUser(request).dataGet(name, dataType);
    }

    public static <T> T getFromAuthUserCustomData(String name, C<T> dataType) {
        return getAuthUser(WebKit.getHttpServletRequest()).dataGet(name, dataType);
    }

    @Note("获取角色字符 Map")
    public static Map<String, ?> getRoleKeyMap(HttpServletRequest request) {
        return getAuthUser(request).getRoleKeyMap();
    }

    public static Map<String, ?> getRoleKeyMap() {
        return getRoleKeyMap(WebKit.getHttpServletRequest());
    }

    public static <T> Map<String, T> getRoleKeyMap(HttpServletRequest request, Class<T> valueType) {
        return getAuthUser(request).getRoleKeyMap(valueType);
    }

    public static <T> Map<String, T> getRoleKeyMap(Class<T> valueType) {
        return getRoleKeyMap(WebKit.getHttpServletRequest(), valueType);
    }

    public static Set<String> getRoleKeySet(HttpServletRequest request) {
        return getAuthUser(request).roleKeySet();
    }

    public static Set<String> getRoleKeySet() {
        return getRoleKeySet(WebKit.getHttpServletRequest());
    }

    public static Collection<?> getRoleValueCollection(HttpServletRequest request) {
        return getAuthUser(request).roleValueCollection();
    }

    public static Collection<?> getRoleValueCollection() {
        return getRoleValueCollection(WebKit.getHttpServletRequest());
    }

    public static <T> Collection<T> getRoleValueCollection(HttpServletRequest request, Class<T> valueType) {
        return getAuthUser(request).roleValueCollection(valueType);
    }

    public static <T> Collection<T> getRoleValueCollection(Class<T> valueType) {
        return getRoleValueCollection(WebKit.getHttpServletRequest(), valueType);
    }

    public static <T> Collection<T> getRoleValueCollection(HttpServletRequest request, C<T> valueType) {
        return getAuthUser(request).roleValueCollection(valueType);
    }

    public static <T> Collection<T> getRoleValueCollection(C<T> valueType) {
        return getRoleValueCollection(WebKit.getHttpServletRequest(), valueType);
    }

    @Note("获取权限字符 Map")
    public static Map<String, ?> getPermKeyMap(HttpServletRequest request) {
        return getAuthUser(request).getPermKeyMap();
    }

    public static Map<String, ?> getPermKeyMap() {
        return getPermKeyMap(WebKit.getHttpServletRequest());
    }

    public static <T> Map<String, T> getPermKeyMap(HttpServletRequest request, Class<T> valueType) {
        return getAuthUser(request).getPermKeyMap(valueType);
    }

    public static <T> Map<String, T> getPermKeyMap(Class<T> valueType) {
        return getPermKeyMap(WebKit.getHttpServletRequest(), valueType);
    }

    public static Set<String> getPermKeySet(HttpServletRequest request) {
        return getAuthUser(request).permKeySet();
    }

    public static Set<String> getPermKeySet() {
        return getPermKeySet(WebKit.getHttpServletRequest());
    }

    public static Collection<?> getPermValueCollection(HttpServletRequest request) {
        return getAuthUser(request).permValueCollection();
    }

    public static Collection<?> getPermValueCollection() {
        return getPermValueCollection(WebKit.getHttpServletRequest());
    }

    public static <T> Collection<T> getPermValueCollection(HttpServletRequest request, Class<T> valueType) {
        return getAuthUser(request).permValueCollection(valueType);
    }

    public static <T> Collection<T> getPermValueCollection(Class<T> valueType) {
        return getPermValueCollection(WebKit.getHttpServletRequest(), valueType);
    }

    public static <T> Collection<T> getPermValueCollection(HttpServletRequest request, C<T> valueType) {
        return getAuthUser(request).permValueCollection(valueType);
    }

    public static <T> Collection<T> getPermValueCollection(C<T> valueType) {
        return getPermValueCollection(WebKit.getHttpServletRequest(), valueType);
    }


    @Note("判断是否拥有指定角色")
    public static boolean hasRole(HttpServletRequest request, String roleKey) {
        return getRoleKeyMap(request).containsKey(roleKey);
    }

    public static boolean hasRole(String roleKey) {
        return hasRole(WebKit.getHttpServletRequest(), roleKey);
    }

    public static boolean hasAllRole(HttpServletRequest request, String... roleKeys) {
        return getAuthUser(request).hasAllRole(roleKeys);
    }

    public static boolean hasAllRole(String... roleKeys) {
        return getAuthUser(WebKit.getHttpServletRequest()).hasAllRole(roleKeys);
    }

    public static boolean hasAllRole(HttpServletRequest request, Iterable<String> roleKeys) {
        return getAuthUser(request).hasAllRole(roleKeys);
    }

    public static boolean hasAllRole(Iterable<String> roleKeys) {
        return getAuthUser(WebKit.getHttpServletRequest()).hasAllRole(roleKeys);
    }


    public static boolean hasAnyRole(HttpServletRequest request, String... roleKeys) {
        return getAuthUser(request).hasAnyRole(roleKeys);
    }

    public static boolean hasAnyRole(String... roleKeys) {
        return getAuthUser(WebKit.getHttpServletRequest()).hasAnyRole(roleKeys);
    }

    public static boolean hasAnyRole(HttpServletRequest request, Iterable<String> roleKeys) {
        return getAuthUser(request).hasAnyRole(roleKeys);
    }

    public static boolean hasAnyRole(Iterable<String> roleKeys) {
        return getAuthUser(WebKit.getHttpServletRequest()).hasAnyRole(roleKeys);
    }


    @Note("判断是否拥有指定权限")
    public static boolean hasPerm(HttpServletRequest request, String permKey) {
        return getPermKeyMap(request).containsKey(permKey);
    }

    public static boolean hasPerm(String permKey) {
        return getPermKeyMap(WebKit.getHttpServletRequest()).containsKey(permKey);
    }

    public static boolean hasAllPerm(HttpServletRequest request, String... permKeys) {
        return getAuthUser(request).hasAllPerm(permKeys);
    }

    public static boolean hasAllPerm(String... permKeys) {
        return getAuthUser(WebKit.getHttpServletRequest()).hasAllPerm(permKeys);
    }

    public static boolean hasAllPerm(HttpServletRequest request, Iterable<String> permKeys) {
        return getAuthUser(request).hasAllPerm(permKeys);
    }

    public static boolean hasAllPerm(Iterable<String> permKeys) {
        return getAuthUser(WebKit.getHttpServletRequest()).hasAllPerm(permKeys);
    }

    public static boolean hasAnyPerm(HttpServletRequest request, String... permKeys) {
        return getAuthUser(request).hasAnyPerm(permKeys);
    }

    public static boolean hasAnyPerm(String... permKeys) {
        return getAuthUser(WebKit.getHttpServletRequest()).hasAnyPerm(permKeys);
    }

    public static boolean hasAnyPerm(HttpServletRequest request, Iterable<String> permKeys) {
        return getAuthUser(request).hasAnyPerm(permKeys);
    }

    public static boolean hasAnyPerm(Iterable<String> permKeys) {
        return getAuthUser(WebKit.getHttpServletRequest()).hasAnyPerm(permKeys);
    }

    @Note("解析 JSON 数组，转为指定泛型的 ArrayList 返回")
    public static <T> List<T> jsonAsArrayList(String json, Class<T> valueType) {
        return jsonArrayAsValue(json, new TypeReference<ArrayList<T>>() {});
    }

    @Note("解析 JSON 数组，转为指定泛型的 HashSet 返回")
    public static <T> HashSet<T> jsonAsHashSet(String json, Class<T> valueType) {
        return jsonArrayAsValue(json, new TypeReference<HashSet<T>>() {});
    }

    @Note("解析 JSON 数组，转为指定泛型的 LinkedHashSet 返回")
    public static <T> LinkedHashSet<T> jsonAsLinkedSet(String json, Class<T> valueType) {
        return jsonArrayAsValue(json, new TypeReference<LinkedHashSet<T>>() {});
    }

    @Note("解析 JSON 数组，转为指定泛型的 TreeSet 返回")
    public static <T> TreeSet<T> jsonAsTreeSet(String json, Class<T> valueType) {
        return jsonArrayAsValue(json, new TypeReference<TreeSet<T>>() {});
    }

    @Note("解析 JSON 数组，转为指定泛型的 ConcurrentHashSet 返回")
    public static <T> ConcurrentHashSet<T> jsonAsConcurrentHashSet(String json, Class<T> valueType) {
        return jsonArrayAsValue(json, new TypeReference<ConcurrentHashSet<T>>() {});
    }

    @Note("解析 JSON 数组，转为指定泛型的 ConcurrentSkipListSet 返回")
    public static <T> ConcurrentSkipListSet<T> jsonAsConcurrentSkipListSet(String json, Class<T> valueType) {
        return jsonArrayAsValue(json, new TypeReference<ConcurrentSkipListSet<T>>() {});
    }


    @Note("将数组类型的 JSON 转为指定类型的值返回")
    public static <T> T jsonArrayAsValue(String json, TypeReference<T> typeReference) {
        if(!VerifyKit.isJsonArray(json)) {
            throw new ValidException(ResultCode.PARAM_ERROR.getResult("参数不是数组类型"));
        }
        return jsonWriteToValue(json, typeReference);
    }


    @Note("将对象类型的 JSON 转为指定类型的值返回")
    public static <T> T jsonObjectAsValue(String json, TypeReference<T> typeReference) {
        if(!VerifyKit.isJsonObject(json)) {
            throw new ValidException(ResultCode.PARAM_ERROR.getResult("参数不是对象类型"));
        }
        return jsonWriteToValue(json, typeReference);
    }


    @Note("实际将 JSON 转为对应的 Java 值")
    public static <T> T jsonWriteToValue(String json, TypeReference<T> typeReference) {
        try {
            return JsonKit.toEntity(json, typeReference);
        } catch (Exception e) {
            throw new ValidException(ResultCode.PARAM_ERROR.getResult("参数校验出错"));
        }
    }


    @Note("读取图片为 Base64 编码")
    public static String readImageToBase64(File imgFile, String mimeType) {
        BufferedImage image = IOKit.readImage(imgFile);
        return IOKit.readToBase64ForImg(image, mimeType);
    }
}
